package code.example.base.reflect.field;

import code.example.base.reflect.BikeProducer;
import code.example.base.reflect.GenerateHuman;
import code.example.tool.LogFactory;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class TestField {


    public void showType(Type type){
        if(type == null){

        }else  if(ParameterizedType.class.isAssignableFrom(type.getClass())){
            ParameterizedType parameterizedType = (ParameterizedType) type;
            String typeName = type.getTypeName();
            LogFactory.getLog().info("ParameterizedType:"+typeName);
            Type[] types = parameterizedType.getActualTypeArguments();
            for(Type param:types){
                showType(param);
            }
            Type rawType =  parameterizedType.getRawType();
            showType(rawType);
        }else if(Class.class.isAssignableFrom(type.getClass())){
            Class classz = (Class)type;
            if(Object.class.equals(classz)){
                return;
            }
            String name =  classz.getCanonicalName();
            LogFactory.getLog().info("className:"+name);

        }else if(TypeVariable.class.isAssignableFrom(type.getClass())){
            TypeVariable typeVariable = (TypeVariable)type;
            String name = typeVariable.getName();
            LogFactory.getLog().info("type:"+name);
        }
    }
    public void getFieldType(Object obj) throws Exception {
        LogFactory.getLog().info("show filed type:");
        Field field =  obj.getClass().getDeclaredField("strList");
        Type type = field.getGenericType();
        showType(type);
        LogFactory.getLog().info("");
    }
    public void setValue(Object obj,int value) throws Exception {
        Field field =  obj.getClass().getDeclaredField("age");
        field.setAccessible(true);
        field.set(obj,value);
        LogFactory.getLog().info("age property set value:"+value);

    }
    public void getValue(Object obj) throws Exception {
        Field field =  obj.getClass().getDeclaredField("age");
        field.setAccessible(true);
        Object value = field.get(obj);
        LogFactory.getLog().info("age property get value:"+value);
    }
    /**
     *  属性是静态绑定，方法是动态绑定
     * @param obj
     * @throws Exception
     */
    public void printAge(Object obj) throws Exception {
        BikeProducer bikeProducer  = (BikeProducer)obj;
        GenerateHuman generateHuman =   GenerateHuman.class.cast(obj);

        LogFactory.getLog().info("this.age="+bikeProducer.age);
        LogFactory.getLog().info("this.age="+bikeProducer.getAge());
        LogFactory.getLog().info("this.age="+generateHuman.getAge());

        LogFactory.getLog().info("parent.age="+generateHuman.age);
        LogFactory.getLog().info("parent.age="+ ((GenerateHuman)obj).age);

    }

    public void parentDeclareField(Object obj) throws Exception {
        Class classz = obj.getClass().getSuperclass();
        LogFactory.getLog().info(" print parent class all filed :");
        Field[] fields = classz.getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            fields[i].setAccessible(true);
            LogFactory.getLog().info(fields[i].getModifiers()+" "+ fields[i].getType()+" "+ fields[i].getName()+",value="+fields[i].get(obj));
        }
        LogFactory.getLog().info(" ");

    }

    /**
     * 获取类 声明的所有属性（Field），
     * @param obj
     * @throws Exception
     */
    public void declareField(Object obj) throws Exception {
        LogFactory.getLog().info(" print all filed (not include parent class) :");
        Field[] fields = obj.getClass().getDeclaredFields();
        for(int i=0;i<fields.length;i++){
            fields[i].setAccessible(true);
            LogFactory.getLog().info(fields[i].getModifiers()+" "+ fields[i].getType()+" "+ fields[i].getName()+",value="+fields[i].get(obj));
        }

        LogFactory.getLog().info(" ");
    }

    /**
     * getFiled 取类及父类所有public 的属性
     * @param obj
     * @throws Exception
     */
    public void publicField(Object obj ) throws Exception {
        LogFactory.getLog().info(" print public filed (include parent class) :");
        Field[] fields = obj.getClass().getFields();
        for(int i=0;i<fields.length;i++){
            LogFactory.getLog().info(fields[i].getModifiers()+" "+ fields[i].getType()+" "+ fields[i].getName()+",value="+fields[i].get(obj));
        }
        LogFactory.getLog().info(" ");
    }
    public Object generate(){
        BikeProducer bikeProducer = new BikeProducer();
        bikeProducer.setCompanyName("大灯车厂");
        bikeProducer.setName("张三");
        return bikeProducer;
    }
    public void test() throws Exception {
        Object obj = generate();

        publicField(obj);
        declareField(obj);
        parentDeclareField(obj);
        printAge(obj);
        setValue(obj,20);
        getValue(obj);
        getFieldType(obj);
    }
    public static void main(String [] args){
        try {
            new TestField().test();
        }catch (Exception e){
            LogFactory.getLog().error(e);
        }
    }
}
